/*global jQuery, Handlebars */
jQuery(function ($) {
    'use strict';

    var Utils = {
        uuid: function () {
            /*jshint bitwise:false */
            var i, random;
            var uuid = '';

            for (i = 0; i < 32; i++) {
                random = Math.random() * 16 | 0;
                if (i === 8 || i === 12 || i === 16 || i === 20) {
                    uuid += '-';
                }
                uuid += (i === 12 ? 4 : (i === 16 ? (random & 3 | 8) : random)).toString(16);
            }

            return uuid;
        },
        pluralize: function (count, word) {
            return count === 1 ? word : word + 's';
        },
        store: function (namespace, data) {
            if (arguments.length > 1) {
                return localStorage.setItem(namespace, JSON.stringify(data));
            } else {
                var store = localStorage.getItem(namespace);
                return (store && JSON.parse(store)) || [];
            }
        }
    };

    var App = {
        init: function () {
            Handlebars.registerHelper('ifCond', function (v1, v2, options) {
                if (v1 === v2) return options.fn(this);
                return options.inverse(this);
            });
            this.ENTER_KEY = 13;
            this.todos = Utils.store('todos-jquery');
            this.cacheElements();
            this.bindEvents();
            this.render();
        },
        cacheElements: function () {
            this.todoTemplate = Handlebars.compile($('#todo-template').html());
            this.footerTemplate = Handlebars.compile($('#footer-template').html());
            this.$todoApp = $('#todoapp');
            this.$header = this.$todoApp.find('#header');
            this.$main = this.$todoApp.find('#main');
            this.$footer = this.$todoApp.find('#footer');
            this.$newTodo = this.$header.find('#new-todo');
            this.$toggleAll = this.$main.find('#toggle-all');
            this.$todoList = this.$main.find('#todo-list');
            this.$count = this.$footer.find('#todo-count');
            this.$clearBtn = this.$footer.find('#clear-completed');
        },
        bindEvents: function () {
            var list = this.$todoList;
            this.$newTodo.on('keyup', this.create);
            this.$toggleAll.on('change', this.toggleAll);
            this.$footer.on('click', '#clear-completed', this.destroyCompleted);
            list.on('change', '.toggle', this.toggle);
            list.on('dblclick', 'label', this.edit);
            list.on('keypress', '.edit', this.blurOnEnter);
            list.on('blur', '.edit', this.update);
            list.on('click', '.destroy', this.destroy);
        },
        render: function (editId) {
            this.$todoList.html(this.todoTemplate({ todos: this.todos, editId: editId }));
            this.$main.toggle(!!this.todos.length);
            this.$toggleAll.prop('checked', !this.activeTodoCount());
            this.renderFooter();
            Utils.store('todos-jquery', this.todos);
        },
        renderFooter: function () {
            var todoCount = this.todos.length;
            var activeTodoCount = this.activeTodoCount();
            var footer = {
                activeTodoCount: activeTodoCount,
                activeTodoWord: Utils.pluralize(activeTodoCount, 'item'),
                completedTodos: todoCount - activeTodoCount
            };

            this.$footer.toggle(!!todoCount);
            this.$footer.html(this.footerTemplate(footer));
        },
        toggleAll: function () {
            var isChecked = $(this).prop('checked');

            $.each(App.todos, function (i, val) {
                val.completed = isChecked;
            });

            App.render();
        },
        activeTodoCount: function () {
            var count = 0;

            $.each(this.todos, function (i, val) {
                if (!val.completed) {
                    count++;
                }
            });

            return count;
        },
        destroyCompleted: function () {
            var todos = App.todos;
            var l = todos.length;

            while (l--) {
                if (todos[l].completed) {
                    todos.splice(l, 1);
                }
            }

            App.render();
        },
        // accepts an element from inside the `.item` div and
        // returns the corresponding todo in the todos array
        getTodo: function (elem, callback) {
            var id = $(elem).closest('li').data('id');

            $.each(this.todos, function (i, val) {
                if (val.id === id) {
                    callback.apply(App, arguments);
                    return false;
                }
            });
        },
        create: function (e) {
            var $input = $(this);
            var val = $.trim($input.val());

            if (e.which !== App.ENTER_KEY || !val) {
                return;
            }

            App.todos.push({
                id: Utils.uuid(),
                title: val,
                completed: false
            });

            $input.val('');
            App.render();
        },
        toggle: function () {
            App.getTodo(this, function (i, val) {
                val.completed = !val.completed;
            });
            App.render();
        },
        edit: function () {
            App.getTodo(this, function (i, val) {
                App.render(val.id);
                var $input = $('[data-id="' + val.id + '"]').find('.edit');
                $input.val($input.val()).focus();
            });
        },
        blurOnEnter: function (e) {
            if (e.which === App.ENTER_KEY) {
                e.target.blur();
            }
        },
        update: function () {
            var val = $.trim($(this).val());

            App.getTodo(this, function (i) {
                if (val) {
                    this.todos[i].title = val;
                } else {
                    this.todos.splice(i, 1);
                }
                this.render();
            });
        },
        destroy: function () {
            App.getTodo(this, function (i) {
                this.todos.splice(i, 1);
                this.render();
            });
        }
    };

    App.init();
});
